package network.dataFormats;
import java.util.Arrays;
import java.util.Vector;

import network.NetworkConstants;
import network.byteConversions.ByteConverter;
/**
 * NetworkData is the byte[] representation of a list of NetworkPackages All sent data are converted from NetworkData to byte[] and then back from byte[] to NetworkData.
 * 
 * @author toni
 * 
 */
public class NetworkData {
	public final static int HEADERSIZE = NetworkConstants.MAXNUMPACKAGES * 4; // An
																				// integer
																				// for
																				// each
																				// byte[]
																				// that
																				// tells
																				// where
																				// in
																				// the
																				// whole
																				// array
																				// the
																				// subarray
																				// begins
	public Vector<NetworkPackage> packages;
	public byte[] data;
	public NetworkData(Vector<NetworkPackage> packages) {
		this.packages = packages;
		assert (packages.size() <= NetworkConstants.MAXNUMPACKAGES);
		createFromPackages();
	}
	public NetworkData(NetworkPackage p) {
		packages = new Vector<NetworkPackage>();
		packages.add(p);
		createFromPackages();
	}
	private void createFromPackages() {
		int length = HEADERSIZE;
		for (NetworkPackage p : packages) {
			length += p.bytes.length;
		}
		data = new byte[length];
		int[] indices = new int[NetworkConstants.MAXNUMPACKAGES];
		for (int i = 0; i < indices.length; i++) {
			indices[i] = -1; // Empty slots will get the index -1
		}
		int position = HEADERSIZE;
		for (int i = 0; i < packages.size(); i++) {
			byte[] pData = packages.get(i).bytes;
			System.arraycopy(pData, 0, data, position, pData.length);
			indices[i] = position;
			position += pData.length;
		}
		byte[] header = makeHeader(indices);
		System.arraycopy(header, 0, data, 0, header.length);
	}
	private byte[] makeHeader(int[] indices) {
		byte[] header = new byte[HEADERSIZE];
		for (int i = 0; i < indices.length; i++) {
			byte[] indexInBytes = ByteConverter.intToBytes(indices[i]);
			header[4 * i] = indexInBytes[0];
			header[4 * i + 1] = indexInBytes[1];
			header[4 * i + 2] = indexInBytes[2];
			header[4 * i + 3] = indexInBytes[3];
		}
		return header;
	}
	public NetworkData(byte[] data) {
		this(data, data.length);
	}
	public NetworkData(byte[] data, int len) {
		this.data = data;
		byte[] header = getHeader(data);
		int[] indices = getIndices(header);
		packages = new Vector<NetworkPackage>();
		for (int i = 0; i < NetworkConstants.MAXNUMPACKAGES; i++) {
			if (indices[i] == -1) { // Index is -1 : Abort here, no more
									// packages
				break;
			}
			if (i == NetworkConstants.MAXNUMPACKAGES - 1 || indices[i + 1] == -1) { // Last package? Data is from
																					// indices[i] to the end of the
																					// array
				packages.add(new NetworkPackage(Arrays.copyOfRange(data, indices[i], len)));
			}
			else {
				packages.add(new NetworkPackage(Arrays.copyOfRange(data, indices[i], indices[i + 1])));
			}
		}
	}
	private byte[] getHeader(byte[] data) {
		return Arrays.copyOfRange(data, 0, HEADERSIZE);
	}
	private int[] getIndices(byte[] header) {
		int[] indices = new int[NetworkConstants.MAXNUMPACKAGES];
		for (int i = 0; i < NetworkConstants.MAXNUMPACKAGES; i++) {
			indices[i] = ByteConverter.fourBytesToInt(header[4 * i], header[4 * i + 1], header[4 * i + 2], header[4 * i + 3]);
		}
		return indices;
	}
	@Override
	public String toString() {
		String s = "<";
		for (NetworkPackage p : packages) {
			s = s + p.toString() + ",";
		}
		s = s + "> (" + data.length + " bytes)";
		return s;
	}
}
